﻿using CoreCms.Net.Auth.Policys;
using CoreCms.Net.Caching.AutoMate.RedisCache;
using CoreCms.Net.IServices;
using CoreCms.Net.Model.ViewModels.UI;
using CoreCms.Net.Utility.Extensions;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Globalization;
using System.Security.Claims;
using System.Threading.Tasks;
using System;
using System.IdentityModel.Tokens.Jwt;
using CoreCms.Net.Model.Entities;
using CoreCms.Net.Model.FromBody;
using CoreCms.Net.Configuration;
using static SKIT.FlurlHttpClient.Wechat.Api.Models.WeDataQueryBindListResponse.Types;
using NETCore.Encrypt;

namespace CoreCms.Net.Web.WebApi.Controllers.AliPayOAuth
{
    /// <summary>
    /// 支付宝业务交互接口
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class AliPayAuthController : ControllerBase
    {
        private readonly IAliPayServices _aliPayService;
        private readonly PermissionRequirement _permissionRequirement;
        private readonly ICoreCmsAliPayUserInfoServices _aliPayUserServices;
        private readonly IRedisOperationRepository _redisOperationRepository;
        private readonly ICoreCmsUserServices _userServices;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ICoreCmsUserLogServices _userLogServices;

        /// <summary>
        /// 构造函数
        /// </summary>
        public AliPayAuthController(PermissionRequirement permissionRequirement, IRedisOperationRepository redisOperationRepository, ICoreCmsAliPayUserInfoServices aliPayUserServices, IAliPayServices aliPayService, ICoreCmsUserServices userServices, IHttpContextAccessor httpContextAccessor, ICoreCmsUserLogServices userLogServices)
        {
            _permissionRequirement = permissionRequirement;
            _redisOperationRepository = redisOperationRepository;
            _aliPayUserServices = aliPayUserServices;
            _aliPayService = aliPayService;
            _userServices = userServices;
            _httpContextAccessor = httpContextAccessor;
            _userLogServices = userLogServices;
        }


        /// <summary>
        /// 静默通过code票据返回app_auth_token相关信息
        /// 前端是getAuthCode方法
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<WebApiCallBack> GetAliPayAppAuthTokenByCode([FromBody] FMStringId entity)
        {
            var jm = new WebApiCallBack();

            var lockKey = "LOCK_OnLogin:user_" + entity.id;
            var lockHolder = Guid.NewGuid().ToString("N"); //锁持有者
            var redisUserLock = await _redisOperationRepository.LockTakeAsync(lockKey, lockHolder, TimeSpan.FromSeconds(10));

            if (redisUserLock)
            {
                if (string.IsNullOrEmpty(entity.id))
                {
                    jm.msg = "请提交code";
                    return jm;
                }

                try
                {
                    var result = _aliPayService.GetAliPayAppAuthTokenBYCode(entity.id);

                    if (!result.IsError)
                    {
                        var userInfo = await _aliPayUserServices.QueryByClauseAsync(p => p.userId == result.UserId);
                        if (userInfo != null)
                        {
                            userInfo.reExpiresIn = result.ReExpiresIn.ObjectToInt();
                            userInfo.expiresIn = result.ExpiresIn.ObjectToInt();
                            userInfo.refreshToken = result.RefreshToken;
                            userInfo.accessToken = result.AccessToken;

                            await _aliPayUserServices.UpdateAsync(userInfo);
                        }
                        else
                        {
                            userInfo = new CoreCmsAliPayUserInfo();
                            //事物处理过程开始
                            userInfo.accessToken = result.AccessToken;
                            userInfo.aliPayUserInfoId = result.AlipayUserId;
                            userInfo.authStart = result.AuthStart;
                            userInfo.expiresIn = result.ExpiresIn.ObjectToInt();
                            userInfo.reExpiresIn = result.ReExpiresIn.ObjectToInt();
                            userInfo.refreshToken = result.RefreshToken;
                            userInfo.userId = result.UserId;
                            userInfo.openId = result.OpenId;
                            userInfo.unionId = result.UnionId;
                            userInfo.createTime = DateTime.Now;
                            userInfo.userInfoId = 0;

                            var resultData = await _aliPayUserServices.InsertAsync(userInfo, true);

                            userInfo.id = resultData;
                        }


                        if (userInfo is { userInfoId: > 0 })
                        {
                            var user = await _userServices.QueryByClauseAsync(p => p.id == userInfo.userInfoId);
                            if (user != null)
                            {
                                if (user.status == (int)GlobalEnumVars.UserStatus.停用)
                                {
                                    jm.status = false;
                                    jm.msg = "您的账号已经被禁用。";
                                    return jm;
                                }

                                if (user.isDelete)
                                {
                                    jm.status = false;
                                    jm.msg = "您的账号已经被禁用。";
                                    return jm;
                                }

                                var claims = new List<Claim> {
                                new Claim(ClaimTypes.Name, user.nickName),
                                new Claim(JwtRegisteredClaimNames.Jti, user.id.ToString()),
                                new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(_permissionRequirement.Expiration.TotalSeconds).ToString(CultureInfo.InvariantCulture)) };

                                //用户标识
                                var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
                                identity.AddClaims(claims);

                                //返回处理结果集
                                var auth = JwtToken.BuildJwtToken(claims.ToArray(), _permissionRequirement);
                                //对token进行非对称加密
                                auth.token = EncryptProvider.AESEncrypt(auth.token, AppSettingsConstVars.JwtConfigSecretKey);

                                jm.status = true;
                                jm.data = new
                                {
                                    auth,
                                    user
                                };
                                jm.otherData = result.UserId;

                                //录入登录日志
                                var log = new CoreCmsUserLog
                                {
                                    userId = user.id,
                                    state = (int)GlobalEnumVars.UserLogTypes.登录,
                                    ip = _httpContextAccessor.HttpContext?.Connection.RemoteIpAddress != null ? _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString() : "127.0.0.1",
                                    createTime = DateTime.Now,
                                    parameters = GlobalEnumVars.UserLogTypes.登录.ToString()
                                };
                                await _userLogServices.InsertAsync(log);

                                return jm;
                            }
                        }
                        jm.status = true;
                        jm.data = result.UserId;
                        jm.otherData = result.UserId;
                    }
                    else
                    {
                        jm.status = false;
                        jm.msg = result.SubMsg;
                        jm.data = result;
                    }

                }
                catch (Exception e)
                {
                    jm.status = false;
                    jm.msg = e.Message;
                    jm.data = e;
                }
                finally
                {
                    await _redisOperationRepository.LockReleaseAsync(lockKey, lockHolder);
                }
            }
            else
            {
                jm.msg = "当前请求太频繁_请稍后再试";
            }
            return jm;
        }

    }
}
